package com.atwisdom.star.core.bsl.customized.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.JsonUtil;
import com.atwisdom.star.common.util.LocalDateTimeUtil;
import com.atwisdom.star.common.vo.StatusCode;
import com.atwisdom.star.core.bsl.customized.ScheduleBusinessBslService;
import com.atwisdom.star.core.bsl.customized.StockBslService;
import com.atwisdom.star.core.bsl.event.EventUtil;
import com.atwisdom.star.core.dao.pojo.modelClass.logic.LogicInstance;
import com.atwisdom.star.core.dsl.functionClass.BatchNumberDslService;
import com.atwisdom.star.core.dsl.modelClass.consume.ConsumeInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.hier.HierInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.logic.Impl.LogicInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.logic.LogicInstanceDslService;
import com.atwisdom.star.core.dsl.modelClass.twins.TwinsInstanceDslService;
import com.atwisdom.star.exception.pojo.BusinessException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 
 * @Date: 2023-08-28 10:54
 */
@Slf4j
@AllArgsConstructor
@Service
public class ScheduleBusinessBslServiceImpl implements ScheduleBusinessBslService {
    private LogicInstanceDslService logicInstanceDslService;
    private EventUtil eventUtil;

    /**
     * 生成保养计划
     * 字段名统一为
     * 保养计划和点巡检计划定时生成对应工单时，
     * 需要在工单增加paramList字段，
     * 30 10 1 * * ?” 每天1点10分30秒触发任务
     */
    // @Scheduled(cron = "0 0 15 * * ?")
    @Scheduled(cron = "0 5 1 * * ? ")
    // @Scheduled(cron = "* */1 * * * ? ")
    @Override
    public void equipmentSchedulePlan() {
        equipmentPlan("equipmentGuardPlan", "PatrolWorkOrder", "patrolStartTime");
        equipmentPlan("EquipmentMaintainPlan", "MaintainWorkOrder", "maintainStartTime");
        equipmentPlan("MouldMaintainPlan", "MouldMaintainWorkOrder", "maintainStartTime");
        equipmentPlan("JigMaintainPlan", "JigMaintainWorkOrder", "maintainStartTime");
        equipmentPlan("EquipBetaGuardPlan", "EquipBetaPatrolWorkOrder", "patrolStartTime");
        equipmentPlan("EquipBetaMaintainPlan", "EquipBetaMaintainWorkOrder", "maintainStartTime");
    }

    public void equipmentPlan(String sourceClassName, String targetClassName,  String startTimeFieldName) {
        String condition = "runStatus = '1' and isApproved = 1 and planStatus in( '0', '1')";
        List<JSONObject> queryJsonList = logicInstanceDslService.queryWithoutHier(condition, sourceClassName, null);
        log.info("query result = {}", queryJsonList);
        for (int i = 0; i < queryJsonList.size(); i++) {
            JSONObject instanceJson = queryJsonList.get(i);
            JSONObject values = instanceJson.getJSONObject("values");
            // 周， 月， 年
            String maintainCycle = values.getString("maintainCycle");
            // ["1", "2", "3"]
            JSONArray planMaintainDate = values.getJSONArray("planMaintainDate");
            if (predicatePeriod(maintainCycle, planMaintainDate)) {
                // JSONObject paramJson = buildEventJson(instanceJson);
                JSONObject paramJson = buildEventJson(instanceJson, targetClassName, startTimeFieldName);
                eventUtil.execute("设备管理", "定时配置生成下游", paramJson);
            }
        }
    }


    /**
     * 改变价表状态
     * 00:05执行一次
     */
    @Scheduled(cron ="0 5 0 * * ? ")
    @Override
    public void changeSupplierPriceStatus() {
        Date today = DateUtil.parse(DateUtil.today());
        String condition = "isApproved = 1 and effectiveStatus in(0,1)";
        List<JSONObject> queryJsonList = logicInstanceDslService.queryWithoutHier(condition, "supplierPrice", null);
        log.info("query result size = {}", queryJsonList.size());
        for (int i = 0; i < queryJsonList.size(); i++) {
            JSONObject instanceJson = queryJsonList.get(i);
            JSONObject values = instanceJson.getJSONObject("values");
            // effectiveDate 价表生效日期 expirationDate 价表失效日期 effectiveStatus 生效状态
            Date effectiveDate = values.getDate("effectiveDate");
            Date expirationDate = values.getDate("expirationDate");
            int expirationResult = DateUtil.compare(expirationDate, today);
            int effectiveDateResult = DateUtil.compare(effectiveDate, today);

            // 设置为失效
            if (expirationResult < 0) {
                values.put("effectiveStatus", 2);
            }
            // 设置为生效
            if (effectiveDateResult >= 0) {
                values.put("effectiveStatus", 1);
            }
            logicInstanceDslService.updateById(instanceJson);
        }
    }

    private JSONObject buildEventJson(JSONObject instanceJson, String targetClassName, String startTimeFieldName ) {
        JSONObject paramJson = new JSONObject();
        JSONArray paramArray = new JSONArray();
        JSONObject paramModel = new JSONObject();
        paramModel.put("name", "model");
        paramModel.put("value", "logic");
        paramArray.add(paramModel);
        JSONObject paramModel2 = new JSONObject();
        paramModel2.put("name", "instanceId");
        paramModel2.put("value", instanceJson.getLong("id"));
        paramArray.add(paramModel2);
        JSONObject paramModel3 = new JSONObject();
        paramModel3.put("name", "parentId");
        paramModel3.put("value", "none");
        paramArray.add(paramModel3);
        JSONObject paramModel4 = new JSONObject();
        paramModel4.put("name", "data");
        JSONArray dataArray = new JSONArray();
        JSONObject dataJson = new JSONObject();
        JSONObject targetJson = new JSONObject();
        targetJson.put("type", "logic");
        targetJson.put("className", targetClassName);
        targetJson.put("parentId", "none");
        JSONObject valuesJson = new JSONObject();
        valuesJson.put("code", "autogen."+targetClassName+"-YYYY");
        valuesJson.put("orderStatus", "0");
        valuesJson.put(startTimeFieldName, "autodate.yyyy-MM-dd HH:mm:ss");
        targetJson.put("values", valuesJson);
        dataJson.put("target", targetJson);
        List<String> propertyMapList = Arrays.asList(
            "master.id:master.sourceId",
            "master.values.name:master.planName",
            "master.values.code:master.sourceCode",
            "master.values.idlingPeriod:master.idlingPeriod",
            "master.values.equipList:master.equipList",
            "master.values.paramList:master.paramList"
        );
        dataJson.put("propertyMapList", propertyMapList);
        dataArray.add(dataJson);
        paramModel4.put("value", dataArray);
        paramArray.add(paramModel4);

        JSONObject paramModel5 = new JSONObject();
        paramModel5.put("name", "updateData");
        JSONArray dataArray5 = new JSONArray();
        JSONObject dataJson5 = new JSONObject();
        JSONObject valuesJson5 = new JSONObject();
        valuesJson5.put("planStatus", "1");
        dataJson5.put("values", valuesJson5);
        dataJson5.put("id", instanceJson.getLong("id"));
        dataArray5.add(dataJson5);
        paramModel5.put("value", dataArray5);
        paramArray.add(paramModel5);

        paramJson.put("params", paramArray);
        paramJson.put("back", new JSONArray());
        return paramJson;
    }

    /**
     * 校验周期是否匹配
     * @param maintainCycle
     * @param planMaintainDate
     * @return
     */
    private boolean predicatePeriod(String maintainCycle, JSONArray planMaintainDate) {
        LocalDateTime now = LocalDateTime.now();
        int dayOfWeek = now.getDayOfWeek().getValue();
        int dayOfMonth = now.getDayOfMonth();
        int month = now.getMonthValue();
        if ("week".equals(maintainCycle)) {
            return planMaintainDate.contains(String.valueOf(dayOfWeek));
        } else if ("month".equals(maintainCycle)) {
            return planMaintainDate.contains(String.valueOf(dayOfMonth));
        } else if ("year".equals(maintainCycle)) {
            return planMaintainDate.contains(String.join("/", String.valueOf(month), String.valueOf(dayOfMonth)));
        } else {
            return false;
        }
    }

}
